perm filename PROLOG.DOC[PRO,LOG] blob
sn#620885 filedate 1981-10-28 generic text, type T, neo UTF8
USER'S GUIDE to DECsystem-10 PROLOG
-----------------------------------
September 1978
Luis Moniz Pereira Fernando C N Pereira & David H D Warren
Divisao de Informatica Department of Artificial Intelligence
Laboratorio Nacional University of Edinburgh
de Engenharia Civil
Lisbon
NB. This issue of the User's Guide descibes the
DECsystem-10 Prolog interpreter version 1.32 and compiler
version 1.11. Comments and suggestions are welcomed.
Page 2
CONTENTS
1. Introduction 3
2. Programming in Logic - the Prolog Language 4
.1 Syntax, Terminology and Informal Semantics 4
.2 Declarative and Procedural Semantics 9
.3 The Cut Symbol 11
.4 Operators 12
3. How to Use the Interpreter 16
.1 'LC' and 'NOLC' Conventions 16
.2 Reading-in Programs 17
.3 Directives 18
.4 Syntax Errors 19
.5 Saving a Program 20
.6 Restoring a Saved Program 20
.7 Program Execution and Interruption 20
.8 Suspending, Saving and Restoring an Execution 21
.9 Tracing 22
.10 Logging 23
.11 Aborting an Execution 23
.12 Exiting from the Interpreter 23
.13 Special Commands 24
4. How to Use the Compiler 25
.1 Basic Use 25
.2 Mode Declarations 28
.3 Linking Together Compiled Modules 29
.4 Running a Compiled Program Stand-Alone 29
5. Built-in Procedures 31
.1 Input/Output 31
.2 Arithmetic 34
.3 Convenience 36
.4 Extra-Control 36
.5 Meta-Logical 38
.6 Internal Database 41
.7 Environmental 42
6. Definite Clause Grammars 45
7. Full Syntax 48
.1 Notation 48
.2 Syntax of Sentences as Terms 49
.3 Syntax of Terms as Token Lists 50
.4 Syntax of Tokens as Character Strings 51
.5 Notes 53
8. Reserved Names 54
9. Examples 55
10. References 60
Page 3
1.0 INTRODUCTION
Prolog is a simple but powerful programming language developed at
the University of Marseille [Roussel 1975], as a practical tool for
←←←←←←←←←
programming in logic [Kowalski 1974] [van Emden 1975] [Colmerauer
1975]. From a user's point of view the major attraction of the
language is ease of programming. Clear, readable, concise programs
can be written quickly with few errors.
The DECsystem-10 Prolog system [Warren 1977] [Warren, Pereira,
Pereira 1977] comprises an interpreter and a compiler, both written
largely in Prolog itself.
The interpreter comprises a superviser ("SVWX") supported by a
run-time system (RTS) consisting of unification routines and built-in
procedures. It reads in and executes Prolog source programs.
The compiler enables a set of Prolog source modules making up a
program to be independently compiled. The compiled modules can then
be automatically loaded, together with modules from the RTS, to
produce a final executable program. Compiled programs are easily
provided with an interpretative interface to the superviser.
The interpreter facilitates the development and testing of Prolog
programs. If a procedure is interpreted, modifications to it can be
incorporated more quickly. Interpreted programs can have access to
compiled procedures.
When compiled, a procedure will run 10 to 20 times faster and use
store more economically. However, it is recommended that the new user
should gain experience with the interpreter before attempting to use
the compiler. It is only worthwhile compiling programs which are
well-tested and are to be used extensively.
NB. In this user's guide we shall assume the "full
character-set" convention ('LC') described in Section 3.1, except
where otherwise stated. When lower-case is not available, the "no
lower-case" ('NOLC') convention must be used. Notice also that
metavariables are underlined. For example, a symbol such as foo may
←←←
be used in the text to refer to some item in the object language,
Prolog.
Page 4
2.0 PROGRAMMING IN LOGIC - THE PROLOG LANGUAGE
This section provides an introduction to the syntax and semantics
of a certain subset of logic ("definite clauses", also known as "Horn
clauses"), and indicates how this subset forms the basis of Prolog.
2.1 Syntax, Terminology And Informal Semantics
2.1.1 Terms -
The data objects of the language are called terms. A term is
←←←←
either a constant, a variable or a compound term.
←←←←←←←← ←←←←←←←← ←←←←←←←← ←←←←
The constants include integers such as:-
←←←←←←←
0 1 999 -512
In DECsystem-10 Prolog, integers are restricted to the range -2↑17 to
2↑17-1, ie. -131072 to 131071. Besides the usual decimal, or base 10,
notation, integers may also be written in any base from 2 to 9, of
which base 2 (binary) and base 8 (octal) are probably the most useful.
As an example of the notation used:-
15 2'1111 8'17
all represent the integer fifteen.
Constants also include atoms such as:-
←←←←
a void = := 'Algol-68' []
The symbol for an atom can be any sequence of characters, which should
be written in quotes if there is possibility of confusion with other
symbols (such as variables, integers). As in conventional programming
languages, constants are definite elementary objects, and correspond
to proper nouns in natural language.
Variables are distinguished by an initial capital letter or by
the initial character "←", eg.
X Value A A1 ←3 ←RESULT
If a variable is only referred to once, it does not need to be named
and may be written as an "anonymous" variable indicated by a single
underline character:-
←
A variable should be thought of as standing for some definite but
unidentified object. This is analogous to the use of a pronoun in
natural language. Note that a variable is not simply a writeable
storage location as in most programming languages; rather it is a
local name for some data object, cf. the variable of pure Lisp and
Page 5
identity declarations in Algol-68.
The structured data objects of the language are the compound
terms. A compound term comprises a functor (called the principal
←←←←←←← ←←←←←←←←←
functor of the term) and a sequence of one or more terms called
arguments. A functor is characterised by its name, which is an atom,
←←←←←←←←← ←←←←
and its arity or number of arguments. For example the compound term
←←←←←
whose functor is named 'point' of arity 3, with arguments X, Y and Z,
is written:-
point(X,Y,Z)
Note that an atom is considered to be a functor of arity 0.
Functors are generally analogous to common nouns in natural
language. One may think of a functor as a record type and the
arguments of a compound term as the fields of a record. Compound
terms are usefully pictured as trees. For example, the term:-
s(np(john),vp(v(likes),np(mary)))
would be pictured as the structure:-
s
np vp
john v np
likes mary
Sometimes it is convenient to write certain functors as operators
←←←←←←←←←
- 2-ary functors may be declared as infix operators and 1-ary functors
←←←←←
as prefix or postfix operators. Thus it is possible to write, eg.
←←←←←← ←←←←←←←
X+Y (P;Q) X<Y +X P;
as optional alternatives to:-
+(X,Y) ;(P,Q) <(X,Y) +(X) ;(P)
The use of operators is described fully in Section 2.4 below.
An important class of data structures are the lists. These are
←←←←
essentially the same as the lists of Lisp. A list either is the
atom:-
[]
representing the empty list, or is a compound term with functor '.'
and two arguments which are respectively the head and tail of the
list. Thus a list of the first three natural numbers is the
structure:-
Page 6
.
1 .
2 .
3 []
which could be written, using the standard syntax, as:-
.(1,.(2,.(3,[])))
but which is normally written, in a special list notation, as:-
[1,2,3]
The special list notation in the case when the tail of a list is a
variable is exemplified by:-
[X,..L] [a,b,..L]
representing:-
. .
X L a .
b L
respectively. These lists may also be written:-
[X|L] [a,b|L]
For convenience, a further notational variant is allowed for
lists of integers which correspond to ASCII character codes. Lists
written in this notation are called strings. An example is:-
←←←←←←
"DECsystem-10"
which represents exactly the same list as:-
[68,69,67,115,121,115,116,101,109,45,49,48]
2.1.2 Programs -
A fundamental unit of a logic program is the goal or procedure
←←←← ←←←←←←←←←
call. Examples are:-
←←←←
gives(tom,apple,teacher) reverse([1,2,3],L) X<Y
Page 7
A goal is merely a special kind of term, distinguished only by the
context in which it appears in the program. The (principal) functor
of a goal is called a predicate. It corresponds roughly to a verb in
←←←←←←←←←
natural language, or to a procedure name in a conventional programming
language.
A logic program consists simply of a sequence of statements
←←←←←←←
called sentences, which are analogous to sentences of natural
←←←←←←←←
language. A sentence comprises a head and a body. The head either
←←←← ←←←←
consists of a single goal or is empty. The body consists of a
sequence of zero or more goals (ie. it too may be empty). If the head
is not empty, the sentence is called a clause.
←←←←←←
If the body of a clause is non-empty, the clause is called a
non-unit clause, and is written in the form:-
←←←←←←←← ←←←←←←
P :- Q, R, S.
← ← ← ←
where P is the head goal and Q, R and S are the goals which make up
← ← ← ←
the body. We can read such a clause either declaratively as:-
←←←←←←←←←←←←←
"P is true if Q and R and S are true."
← ← ← ←
or procedurally as:-
←←←←←←←←←←←←
"To satisfy goal P, satisfy goals Q, R and S."
← ← ← ←
If the body of a clause is empty, the clause is called a unit
←←←←
clause, and is written in the form:-
←←←←←←
P.
←
where P is the head goal. We interpret this declaratively as:-
←
"P is true."
←
and procedurally as:-
"Goal P is satisfied."
←
A sentence with an empty head is called a directive, of which the
←←←←←←←←←
most important kind is called a question and is written in the form:-
←←←←←←←←
?- P, Q.
← ←
where P and Q are the goals of the body. Such a question is read
← ←
declaratively as:-
"Are P and Q true?"
← ←
and procedurally as:-
Page 8
"Satisfy goals P and Q."
← ←
Sentences generally contain variables. Note that variables in
different sentences are completely independent, even if they have the
same name - ie. the "lexical scope" of a variable is limited to a
single sentence. Each distinct variable in a sentence should be
interpreted as standing for an arbitrary entity, or value. To
illustrate this, here are some examples of sentences containing
variables, with possible declarative and procedural readings:-
(1) employed(X) :- employs(Y,X).
"Any X is employed if any Y employs X."
"To find whether a person X is employed,
find whether any Y employs X."
(2) derivative(X,X,1).
"For any X, the derivative of X with respect to X is 1."
"The goal of finding a derivative for the expression X with
respect to X itself is satisfied by the result 1."
(3) ?- ungulate(X), aquatic(X).
"Is it true, for any X, that X is an ungulate and X is
aquatic?"
"Find an X which is both an ungulate and aquatic."
In any program, the procedure for a particular predicate is the
←←←←←←←←←
sequence of clauses in the program whose head goals have that
predicate as principal functor. For example, the procedure for a
ternary predicate 'concatenate' might well consist of the two
clauses:-
concatenate([X,..L1],L2,[X,..L3]) :- concatenate(L1,L2,L3).
concatenate([],L,L).
where 'concatenate(L1,L2,L3)' means "the list L1 concatenated with the
list L2 is the list L3".
Certain predicates are predefined by built-in procedures supplied
←←←←←←←← ←←←←←←←←←
by the Prolog system. Such predicates are called evaluable
←←←←←←←←←
predicates.
←←←←←←←←←
As we have seen, the goals in the body of a sentence are linked
by the operator ',' which can be interpreted as conjunction ("and").
It is sometimes convenient to use an additional operator ';', standing
for disjunction ("or"). (The precedence of ';' is such that it
dominates ',' but is dominated by ':-'). An example is the clause:-
Page 9
grandfather(X,Z) :-
(mother(X,Y); father(X,Y)), father(Y,Z).
which can be read as:-
"For any X, Y and Z,
X has Z as a grandfather if
either the mother of X is Y or the father of X is Y,
and the father of Y is Z.
Such uses of disjunction can always be eliminated by defining an
extra predicate - for instance the previous example is equivalent to:-
grandfather(X,Z) :- parent(X,Y), father(Y,Z).
parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).
- and so disjunction will not be mentioned further in the following,
more formal, description of the semantics of clauses.
2.2 Declarative And Procedural Semantics
The semantics of definite clauses should be fairly clear from the
informal interpretations already given. However it is useful to have
a precise definition. The declarative semantics of definite clauses
←←←←←←←←←←← ←←←←←←←←←
tells us which goals can be considered true according to a given
program, and is defined recursively as follows.
A goal is true if it is the head of some clause instance and
←←←←
each of the goals (if any) in the body of that clause
instance is true, where an instance of a clause (or term) is
←←←←←←←←
obtained by substituting, for each of zero or more of its
variables, a new term for all occurrences of the variable.
For example, if a program contains the preceding procedure for
'concatenate', then the declarative semantics tells us that:-
concatenate([a],[b],[a,b])
is true, because this goal is the head of a certain instance of the
first clause for 'concatenate', namely,
concatenate([a],[b],[a,b]) :- concatenate([],[b],[b]).
and we know that the only goal in the body of this clause instance is
true, since it is an instance of the unit clause which is the second
clause for 'concatenate'.
Page 10
Note that the declarative semantics makes no reference to the
sequencing of goals within the body of a clause, nor to the sequencing
of clauses within a program. This sequencing information is, however,
very relevant for the procedural semantics which Prolog gives to
←←←←←←←←←← ←←←←←←←←←
definite clauses. The procedural semantics defines exactly how the
Prolog system will execute a goal, and the sequencing information is
the means by which the Prolog programmer directs the system to execute
his program in a sensible way. The effect of executing a goal is to
enumerate, one by one, its true instances. Here then is an informal
definition of the procedural semantics.
To execute a goal, the system searches for the first clause
←←←←←←←
whose head matches or unifies with the goal. The
←←←←←←← ←←←←←←←
unification process [Robinson 1965] finds the most general
←←←←←←←←←←←
common instance of the two terms, which is unique if it
exists. If a match is found, the matching clause instance
is then activated by executing in turn, from left to right,
←←←←←←←←←
each of the goals (if any) in its body. If at any time the
system fails to find a match for a goal, it backtracks, ie.
←←←←←←←←←←
it rejects the most recently activated clause, undoing any
substitutions made by the match with the head of the clause.
Next it reconsiders the original goal which activated the
rejected clause, and tries to find a subsequent clause which
also matches the goal.
For example, if we execute the goal expressed by the question:-
?- concatenate(X,Y,[a,b]).
we find that it matches the head of the first clause for
'concatenate', with X instantiated to [a,..X1]. The new variable X1 is
constrained by the new goal produced, which is the recursive procedure
call:-
concatenate(X1,Y,[b])
Again this goal matches the first clause, instantiating X1 to
[b,..X2], and yielding the new goal:-
concatenate(X2,Y,[])
Now this goal will only match the second clause, instantiating both X2
and Y to []. Since there are no further goals to be executed, we have
a solution:-
X = [a,b]
Y = []
ie. a true instance of the original goal is:-
concatenate([a,b],[],[a,b])
If this solution is rejected, backtracking will generate the further
solutions:-
Page 11
X = [a]
Y = [b]
X = []
Y = [a,b]
in that order, by re-matching, against the second clause for
'concatenate', goals already solved once using the first clause.
2.3 The Cut Symbol
Besides the sequencing of goals and clauses, Prolog provides one
other very important facility for specifying control information.
This is the cut symbol, written '!'. It is inserted in the program
←←←
just like a goal, but is not to be regarded as part of the logic of
the program and should be ignored as far as the declarative semantics
is concerned.
The effect of the cut symbol is as follows. When first
encountered as a goal, cut succeeds immediately. If backtracking
should later return to the cut, the effect is to fail the "parent
goal", ie. that goal which matched the head of the clause containing
the cut, and caused the clause to be activated. In other words, the
cut operation commits the system to all choices made since the parent
←←←←←←←
goal was invoked, and causes other alternatives to be discarded. The
goals thus rendered "determinate" are the parent goal itself, any
goals occurring before the cut in the clause containing the cut, and
any subgoals which were executed during the execution of those
preceding goals.
Examples:-
(1) member(X,[X,..L]) :- !.
member(X,[Y,..L]) :- member(X,L).
The only result producing by executing:-
?-member(X, [a,b,c]).
is X=a, the other two potential solutions being discarded.
(2) compile(S,R) :- parse(S,T), !, translate(T,R).
The procedure 'compile' only calls 'translate' for the first solution
produced by 'parse'. Alternative solutions which 'parse' might produce
are discarded.
Page 12
2.4 Operators
The Prolog syntax caters for operators of three main kinds -
infix, prefix and postfix. Each operator has a precedence, which is a
←←←←←←←←←←
number from 1 to 1200. The precedence is used to disambiguate
expressions where the structure of the term denoted is not made
explicit through the use of brackets. The general rule, in an
otherwise ambiguous subexpression, is that it is the operator with the
HIGHEST precedence that is the principal functor. Thus if '+' has a
higher precedence than '/', then
a+b/c a+(b/c)
are equivalent and denote the term '+(a,/(b,c))'. Note that the infix
form of the term '/(+(a,b),c)' must be written with explicit brackets,
ie.
(a+b)/c
If there are two operators in the subexpression having the same
highest precedence, the ambiguity must be resolved from the types of
←←←←
the operators. The possible types for an infix operator are:-
xfx xfy yfx
With an operator of type 'xfx', it is a requirement that both of the
two subexpressions which are the arguments of the operator must be of
LOWER precedence than the operator itself, ie. their principal
functors must be of lower precedence, unless the subexpression is
explicitly bracketed (which gives it zero precedence). With an
operator of type 'xfy', only the first or left-hand subexpression must
be of lower precedence; the second can be of the SAME precedence as
the main operator; and vice versa for an operator of type 'yfx'.
For example, if the operators '+' and '-' both have type 'yfx'
and are of the same precedence, then the expression:-
a-b+c
is valid, and means:-
(a-b)+c ie. +(-(a,b),c)
Note that the expression would be invalid if the operators had type
'xfx', and would mean:-
a-(b+c) ie. -(a,+(b,c))
if the types were both 'xfy'.
The possible types for a prefix operator are:-
fx fy
Page 13
and for a postfix operator they are:-
xf yf
The meaning of the types should be clear by analogy with those for
infix operators. As an example, if 'not' were declared as a prefix
operator of type 'fy', then:-
not not P
would be a permissible way to write 'not(not(P))'. If the type were
'fx', the preceding expression would not be legal, although:-
not P
would still be a permissible form for 'not(P)'.
In DECsystem-10 Prolog, a functor named name is declared as an
←←←←
operator of type type and precedence precedence by the command:-
←←←← ←←←←←←←←←←
:-op(precedence,type,name).
←←←←←←←←←← ←←←← ←←←←
The argument name can also be a list of names of operators of the same
←←←←
type and precedence.
It is possible to have more than one operator of the same name,
so long as they are of different kinds, ie. infix, prefix or postfix.
An operator of any kind may be redefined by a new declaration of the
same kind. This applies equally to operators which are provided as
standard in DECsystem-10 Prolog, namely:-
←←←←←←←←
Page 14
:-op( 1200, xfx, [:-,-->]).
:-op( 1200, fx, [:-,?-]).
:-op( 1100, xfy, ';' ).
:-op( 1100, xf, ';' ).
:-op( 1050, xfy, -> ).
:-op( 1001, fx, mode ).
/* :-op( 1000, xfy, ',' ). See note below. */
:-op( 700, xfx, [=,==,\==,is,<,>,=<,>=,=:=,=\=]).
:-op( 700, xfy, [:=,+:=]).
:-op( 500, yfx, [+,-,/\,\/]).
:-op( 500, fx, [+,-]).
:-op( 400, yfx, [*,/,<<,>>]).
:-op( 300, xfx, mod ).
Note that a comma written literally as a punctuation character
can be used as though it were an infix operator of precedence 1000 and
type 'xfy', ie.
X,Y ','(X,Y)
represent the same compound term. But note that a comma written as a
quoted atom is NOT a standard operator.
Note also that the arguments of a compound term written in
standard syntax must be expressions of precedence BELOW 1000. Thus it
is necessary to bracket the expression 'P:-Q' in:-
assert((P:-Q))
Note carefully the following syntax restrictions, which serve to
remove potential ambiguity associated with prefix operators.
(1) In a term written in standard syntax, the principal functor and
its following '(' must NOT be separated by any intervening spaces,
newlines etc. Thus:-
point (X,Y,Z)
is invalid syntax.
(2) If the argument of a prefix operator starts with a '(', this '('
must be separated from the operator by at least one space or other
non-printable character. Thus:-
Page 15
:-(p;q),r.
is invalid syntax, and must be written as eg.
:- (p;q),r.
(3) If a prefix operator is written without an argument, as an
ordinary atom, the atom is treated as an expression of the same
precedence as the prefix operator, and must therefore be bracketed
where necessary. Thus the brackets are necessary in:-
X = (?-)
Page 16
3.0 HOW TO USE THE INTERPRETER
To run the interpreter under the TOPS-10 Monitor with virtual
memory, perform the Monitor command:-
R PROLOG
{If your installation doesn't have Prolog in the system (SYS) area,
type instead RUN PROLOG[p,pn] , where [p,pn] is the Prolog area.⎇
← ←← ← ←←
The interpreter responds with a message of identification and the
prompt '|' as soon as it is ready to accept input. At this point the
interpreter is expecting input of a directive, ie. a question or
command. This state is called interpreter top level.
←←←←←←←←←←← ←←← ←←←←←
Note If the TOPS-10 Monitor at your installation does not
←←←←
have the virtual memory option, you should specify in the R
command the amount of core your program will need for
stacks. Thus, you should call Prolog with:-
R PROLOG nK
←
where n-2 should be the stack requirements. A value of 10
←
for n is ample for most uses. If, however, a running
←
program requires more than the allocated amount, the error
message
! stack space full
is issued and the execution aborted. If your program was
not in an infinite recursion due to a programming error, you
should try to run Prolog with a higher value of n.
←
If your terminal does not provide lower-case characters, you must
first of all type the command:-
:-'NOLC'.
and then observe the "no lower-case" convention described in the
following section.
3.1 'LC' And 'NOLC' Conventions
The standard syntax of Prolog assumes that a full ASCII character
set is available. With this "full character set" or 'LC' convention,
variables are (normally) distinguished by an initial capital letter,
while atoms and other functors must start with a lower-case letter
(unless enclosed in single quotes).
When lower-case is not available, the "no lower-case" or 'NOLC'
convention has to be adopted. With this convention, variables must be
distinguished by an initial underline character "←", and the names of
atoms and other functors, which now have to be written in upper-case,
Page 17
are implicitly translated into lower-case (unless enclosed in single
quotes). For example:-
←VALUE2
is a variable, while
VALUE2
is 'NOLC' convention notation for the atom which is identical to:-
value2
written in the 'LC' convention.
The default convention is 'LC'. To switch to the "no lower-case"
convention, call the built-in procedure 'NOLC', eg. by the command:-
:-'NOLC'.
To switch back to the "full character set" convention, call the
built-in procedure 'LC', eg. by:-
:-'LC'.
Note that the names of these two procedures consist of upper-case
letters (so that they can be referred to on all devices), and
therefore the names must ALWAYS be enclosed in single quotes.
3.2 Reading-in Programs
A program is made up of a sequence of clauses, possibly
interspersed with directives to the interpreter. The clauses of a
procedure do not have to be immediately consecutive, but remember that
their relative order may be important. The text of a program is
normally created separately in a file (or files), using a text editor.
To input a program from a file file, give the special command:-
←←←←
[file].
←←←←
which will instruct the interpreter to read-in the program. If the
file has some extension, its name is "PROG.PL" say, it is necessary to
give the complete filename between single quotes. When the end of
file or the special command ":-end." are found in file, the
←←←←
interpreter displays on the terminal the time spent for read-in and
the number of words occupied by the program. This indicates the
completion of the command.
Page 18
Clauses may also be typed in directly at the terminal, (although
this is only recommended if the clauses will not be needed
permanently, and are few in number). To enter clauses at the terminal,
you must give the special command:-
[user].
The interpreter is now in a state where it expects input of clauses or
directives. To return to interpreter top level, give the special
command:-
:-end.
or alternatively just type ↑Z. Either of these causes an end of file
for the ersatz file 'user', and end of file terminates program
read-in.
3.3 Directives
Directives are either commands or questions. Both are ways of
directing the system to execute some goal or goals.
Suppose list membership has been defined by:-
member(X,[X,..←]).
member(X,[←,..L]) :- member(X,L).
Note the use of anonymous variables written "←". The command:-
:- member(3,[1,2,3]), write(yes).
directs the system to check whether 3 belongs to the list [1,2,3], and
to output "yes" if so. Execution of a command terminates when all the
goals in the command have been successfully executed. Other
alternative solutions are not sought; one may imagine an implicit
"cut" at the end of the command. If no solution can be found, the
system gives:-
?
as a warning.
The syntax of a question is the same as a command, except that it
is introduced by "?-" instead of ":-". If the specified goal(s) can be
satisfied, the final value of each distinct variable is displayed
(except for anonymous variables). The system then pauses awaiting
input of a single character, followed by <cr> (carriage return), from
the user. If the character is ";", the system backtracks to find an
alternative solution. If no more solutions can be found it outputs:-
no
Page 19
and execution of the question is complete. If the user does not wish
to see any alternative solutions, he must input a printable character
other than ";" to stop the execution. If a question can be satisfied
but contains no variables, then the system answers
yes
and execution of the question terminates.
NB. At interpreter top level, but NOT during program read-in
(whether from 'user' or from a file), a question may be abbreviated by
omitting the '?-'. Thus, any term typed in which is neither a list nor
has ':-' as principal functor, is taken as a question.
The outcome of some questions is shown below, where a number
preceded by "←" is a system-generated name for a variable.
?- member(X,[tom,dick,harry]).
X = tom;
X = dick;
X = harry;
no
?- member(X,[a,b,f(Y,c)]),member(X,[f(b,Z),d]).
Y = b,
X = f(b,c),
Z = c.
?- member(X,[f(←),g]).
X = f(←1728).
?- member(b,[a,b,c]).
yes
3.4 Syntax Errors
Syntax errors are detected during reading. Each clause,
directive or in general any term read-in by the built-in procedure
'read' that fails to comply to syntax requirements is displayed on the
terminal as soon as it is read. A mark indicates the point in the
string of symbols where the parser has failed to continue analysis.
eg.
member(X,X:L).
gives:-
*** syntax error ***
member(X,X
*** here ***
: L).
Page 20
if ':' has not been declared as an infix operator.
3.5 Saving A Program
Once a program has been read, the interpreter will have available
all the information necessary for its execution. This information is
called a program state.
←←←←←
The state of a program may be saved on disk for future execution.
To save a program into a file file, perform the command:-
←←←←
?-save(file).
←←←←
3.6 Restoring A Saved Program
Once a program has been saved into a file file, the following
←←←←
command will restore the interpreter to the saved state:-
?-restore(file).
←←←←
After execution of this command, which may be given in the same
session or at some future date, the interpreter will be in EXACTLY the
same state as existed immediately prior to the call to 'save'. For
example, upon completion of a 'restore', the character convention in
force will be that which was previously saved.
Note that when a new version of the Prolog system is installed,
all program files saved with the old version become obsolete.
3.7 Program Execution And Interruption
Execution of a program is started by giving the interpreter a
directive which contains a call to one of the program's procedures.
Only when execution of one directive is complete does the
interpreter become ready for another directive. However, one may
interrupt the normal execution of a directive by typing ↑C (control C)
if the system is in input wait, or ↑C↑C (two control Cs) if it is
running. This ↑C interruption has the effect of suspending the
←← ←←←←←←←←←←←←
execution, and the following message is displayed:-
Function (H for help):
Page 21
At this point the interpreter accepts one-letter commands
corresponding to certain actions. To execute an action simply type
the corresponding character (lower or upper case) followed by <cr>.
The possible commands are:-
B, break the current execution;
C, continue the execution;
E, exit from Prolog, closing all files;
G, switch garbage collection (initially on);
H, list available commands;
M, break to Monitor level (use Monitor command 'CONT' to
proceed);
N, disable trace;
T, enable trace.
The use of these commands is explained in the sections that follow.
If when trying to interrupt a program with ↑C you accidentally
get to Monitor level, (perhaps because you typed too many ↑Cs), type
'CONT' to proceed.
3.8 Suspending, Saving, And Restoring An Execution
When the execution of a program is interrupted, all the
information necessary for continuing the execution is still retained
by the interpreter. This information constitutes the state of the
←←←←←
execution.
The state of an execution may be saved and restored in exactly
the same way as program states, by means of the 'save' and 'restore'
commands. Thus, if you want to save into a file file the state of an
←←←←
execution for future resumption then, after a ↑C interruption, type B
(break) followed by <cr>. This will cause the interpreter to suspend
execution immediately prior to the next call to an INTERPRETED
procedure. The message:-
% break:
will then be displayed. This signals the start of a break, and except
←←←←←
for the effect of 'abort's (see below), it is as if the interpreter
was at top level.
You can now save the state with the directive:-
?-save(file).
←←←←
A ":-end." command or a ↑Z character will close the break and
resume the execution which was suspended. Execution will be resumed
at the procedure call where it had been suspended.
Page 22
A suspended execution can be aborted by issuing the command:-
:-abort.
within the break; see Section 3.11 below.
A break may also be produced by calling the built-in procedure
'break' anywhere within a program. Breaks may be nested within other
breaks.
3.9 Tracing
The Prolog interpreter provides a tracing facility. When tracing
is enabled, each procedure call in an interpreted clause is displayed
on the terminal with the current values of its arguments. This
information is preceded by a number with a "-" sign, which indicates
the invocation level of the goal being displayed. (The invocation
←←←←←←←←←← ←←←←←
level of each of the goals of a clause is one greater than that of the
goal which activated the clause. The first level is zero.) Also, each
time execution of a goal is successfully completed, it is displayed
again with the new current values of all its arguments. Again the
level of the goal is indicated, this time preceded by a "+" sign.
For example, the question:-
?-concatenate([a,b],[c,d],L).
when traced produces:-
-0 concatenate([a,b],[c,d],←202)
-1 concatenate([b],[c,d],←328)
-2 concatenate([],[c,d],←338)
+2 concatenate([],[c,d],[c,d])
+1 concatenate([b],[c,d],[b,c,d])
+0 concatenate([a,b],[c,d],[a,b,c,d])
L = [a,b,c,d]
Tracing has two modes, 'leashed' and 'unleashed'. When tracing in
'leashed' mode, a '?' prompt is issued immediately after each traced
call to an INTERPRETED procedure. A one-letter response followed by
<cr> must then be given, choosing amongst various tracing and
execution options. Possible responses are:-
A, abort the execution;
B, suspend the execution, entering a break;
C, continue tracing;
F, fail this goal;
H, list available options;
N, switch off tracing;
S, skip tracing of this goal;
U, switch to 'unleashed' tracing.
Page 23
Tracing is enabled by the command:-
:-trace.
and 'leashed' mode is enabled by:-
:-leash.
Tracing is disabled by the command:-
:-notrace.
and 'leashed' mode is disabled by:-
:-unleash.
The defaults are tracing off, and 'leashed' mode for tracing.
Tracing may also be enabled or disabled by typing T (trace) or N
(notrace) respectively, and <cr>, following a ↑C interruption.
Certain goals are never traced, namely:-
primitive I/O (eg. 'get'),
'write',
trace control (eg. 'notrace'),
and also any goal which is not logically atomic (eg. conjunctions,
disjunctions, 'true').
3.10 Logging
When Prolog is entered, all terminal interaction is automatically
written to the file PROLOG.LOG in append mode (ie., if PROLOG.LOG
already exists, the new data is appended to it). This facility can be
switched off by calling the evaluable predicate 'nolog', and on again
by calling 'log'.
3.11 Aborting An Execution
To abort the current execution, ie. to force an immediate
failure of the directive currently being executed to interpreter top
level, call the evaluable predicate 'abort', either from the program
or by executing the command:-
:-abort.
within a break. In this case no ":-end." or ↑Z is needed to close the
break.
Page 24
3.12 Exiting From The Interpreter
To exit from the interpreter and return to monitor level either
call the built-in procedure 'halt', type ":-end." or ↑Z at interpreter
top level, or use the E (exit) command following a ↑C interruption.
3.13 Special Commands
The special command:-
:-end.
terminates a break, a program file, or exits to the Monitor from
interpreter top level. It is equivalent to ↑Z or end of file.
Programs from one or more files may be read-in by giving, as a
special command, simply a list of the names of the files. (The case
where there is just one name in the list has already been described
above). A file name may optionally be preceded by the operator '-' to
indicate that the file should be "reconsulted" rather than
"consulted". (The built-in procedures 'consult' and 'reconsult' for
reading-in programs are described fully in Section 5.1). A special
command such as:-
[file1,-file2,file3].
is thus merely a shorthand for:-
:-consult(file1),reconsult(file2),consult(file3).
Page 25
4.0 HOW TO USE THE COMPILER
The DECsystem-10 Prolog compiler [Warren 1977] produces compact
and efficient code, running 10 to 20 times faster than interpreter
code, and requiring much less runtime storage (stacks). Compiled
Prolog programs are comparable in efficiency with Lisp programs for
the same task, compiled by current DECsystem-10 Lisp compilers [Warren
& al. 1977].
Although compiled code is as safe as interpreted programs (ie.,
←←←←
no unpredictable errors or results are possible - barring system
bugs!), it is not advisable to compile untested programs, because
compilation takes more time (both yours and the machine's), and
because currently there are no debugging aids for compiled code.
Note that a compiled procedure can NOT be augmented or modified
at runtime with interpreted clauses.
When you are going to the trouble of compiling a program, it is
often worthwhile including optional mode declarations to inform the
←←←← ←←←←←←←←←←←
compiler that certain procedures will only be used in restricted ways,
ie. that some arguments in the call will always be "input", while
others will always be "output". Such information enables the compiler
to generate more compact code making better use of runtime storage.
The saving of runtime storage in particular can often be very
substantial. Mode declarations also help other people to understand
how your program operates. Full details of mode declarations are
given in Section 4.2.
4.1 Basic Use
You should have library access to the Prolog area. To get it
(under the TOPS-10 Monitor), either incant:-
.R SETSRC
*LIB:[p,pn]
← ←←
*↑C
.
or include in your SWITCH.INI file the line:-
LOGIN /LIB:[p,pn]
← ←←
where [p,pn] is the Prolog area.
← ←←
A Prolog program to be compiled may be split into several files,
which are called modules. The compiler creates a file containing
←←←←←←
information common to all modules of a program, which is called the
functors file. The user has to give the program some name name; the
←←←←←←←← ←←←← ←←←←
functors file is then called name.FNS.
←←←←
Page 26
One should include in the main module of the program the compiler
directive:-
:-program(modules,interactives).
←←←←←←← ←←←←←←←←←←←←
where modules is a list of the other modules in the program, and
←←←←←←←
interactives is a list of the predicates defined in this module which
←←←←←←←←←←←←
are to be made "interactive", ie. accessible to the interpreter. For
example, if there are no other modules and the predicates 'tom(←)',
'dick(←,←)' and 'harry', defined in the main module, are to be made
interactive, then the appropriate directive is:-
:-program([],[tom(1),dick(2),harry(0)]).
If there are other modules besides the main one, their names must
be listed as the first argument of the 'program' directive, and in
addition a compiler directive of the following type must be included
in each auxiliary module:-
:-module(module-name,interactives).
←←←←←←←←←←← ←←←←←←←←←←←←
where module-name is the name of the module (only the first 6
←←←←←←←←←←←
characters are significant), and interactives is again the list of
←←←←←←←←←←←←
predicates defined within the module which are to be made interactive.
For example:-
:-module(extras,[rag(3),tag(2),bobtail(1)]).
All interactive predicates may be directly invoked from
interpreted clauses (including directives entered on-line). A compiled
clause may directly invoke any of the predicates defined in the same
module, and any evaluable predicate. Any interactive predicate (which
includes also evaluable predicates and predicates defined by
interpreted clauses) may be invoked anywhere by use of the built-in
predicate 'call(←)', eg.
call(bobtail(X))
Non-interactive compiled predicates are generally only accessible in
the module in which they are defined, but see Section 4.3 below.
Use of a variable, such as 'P', as a goal is equivalent to the
goal:-
call(P)
At the time of execution, P must be instantiated to a goal of which
the predicate is interactive, (or, more generally, to a conjunction,
disjunction etc. of such goals).
Page 27
To compile a program, to be called name, comprising say modules
←←←←
main, module1 and module2, you should type the following (where the
←←←← ←←←←←←← ←←←←←←←
":" and "program:" characters are prompts from the Prolog compiler):-
R PLC
program:name
←←←←
:main
←←←←
:module1
←←←←←←←
:module2
←←←←←←←
:]]
{If your installation doesn't have the Prolog compiler in the system
(SYS) area, the first line must be .RUN PLC[p,pn], where [p,pn] is the
← ←← ← ←←
Prolog area. Also note that if the Monitor at your installation
doesn't have virtual memory, you should give a core argument when
calling the compiler, as described for the interpreter in Section
3.0.⎇.
Now, the the following message may occur:-
No new functors. Do you still want name.REL?
←←←←
If there is no such file in your area, or if for any reason you think
the existing file is not up-to-date, answer "Y", else answer "N", both
to be followed by <cr>.
A module name can have the form either file.ext or else just
←←←← ←←←
file. In the latter case the extension 'PL' is implied.
←←←←
During compilation, some files with extension '.TPL' are created.
At the end of the compilation, all files with that extension are
←←←
deleted (so it is better if you do not use that extension for your own
purposes!).
To get a core image of the compiled program together with the
interpreter (which is like an augmented interpreter), compile the
program as described before and then execute the Monitor commands:-
LOAD name,main,module1,module2
←←←← ←←←← ←←←←←←← ←←←←←←←
SAVE name
←←←←
To run your core image, just do:-
RUN name
←←←←
{An example of the load sequence is:-
LOAD MYJOB,MASTER,SLAVE1,SLAVE2
SAVE MYJOB
⎇.
Page 28
If you want to recompile some modules of your program, run PLC
giving only the names of those modules. When you come to load the
core image, the names of all modules must be listed however. Note
that a module which has syntax errors is analysed but no object file
is produced for it.
If you only want to compile a subset of the modules of a program,
and to leave compilation of the others til later, end the compilation
with a single "]" instead of "]]". Otherwise time will be wasted in
compiling an incomplete version of the functors file. DO, however,
make sure that an up-to-date version of the functors file is
ultimately compiled, by ending the final compilation before loading
with "]]". (NB. If you forget this, unpredictable errors will occur
during loading or running the program!)
4.2 Mode Declarations
A mode declaration is given by a compiler directive of the form:-
:-mode predicate(modes).
←←←←←←←←← ←←←←←
where predicate is the name of a procedure, and modes specifies the
←←←←←←←←← ←←←←←
"modes" of its arguments. modes consists of a number of "mode items",
←←←←←
separated by commas, one for each argument position of the predicate
concerned. A mode item is either '+', '-' or '?'. Mode '+' specifies
that the corresponding argument in any call to the procedure will
always be instantiated to a NON-variable, while mode '-' specifies
that the argument will always be instantiated to a VARIABLE. Mode '?'
indicates that there is no restriction on the form of the argument; a
mode declaration such as:-
:-mode concatenate(?,?,?).
is equivalent to omitting the declaration altogether.
If, for example, you know that the first two arguments of the
procedure 'concatenate' will always be "input", you can give it the
mode declaration:-
:-mode concatenate(+,+,?).
If, in addition, you are prepared to guarantee that the third argument
will always be "output", you can strengthen the mode declaration to:-
:-mode concatenate(+,+,-).
To have any effect, a mode declaration must appear before the
clauses of the procedure it concerns. If, at runtime, a procedure
call violates the restriction imposed by a mode declaration, EITHER
this will cause an error message to be given and the call to fail, OR
the call will proceed normally - which alternative occurs is
implementation defined. Mode declarations are ignored by the
Page 29
interpreter.
4.3 Linking Compiled Modules Together
The predicates defined in a module can be made directly
←←←←←←←←
accessible to other modules (i.e. without going through the
interpreter) if some extra directives are given to the compiler.
To make the predicate predicate of n arguments accessible, the
←←←←←←←←← ←
directives:-
:-ext(predicate,n,name).
←←←←←←←←← ← ←←←←
:-entry(predicate,n).
←←←←←←←←← ←
should be given in the module where the predicate is defined; and the
directive:-
:-ext(predicate,n,name).
←←←←←←←←← ← ←←←←
must be given in each module which refers to the predicate. The name
←←←←
must be a unique external name of up to six characters, not containing
'$' (and, for the time being, not beginning with 'P'). Upper and lower
case letters are treated as equivalent.
NB. The 'ext' directive MUST precede any other reference in the
module to the corresponding predicate, INCLUDING references in
'entry', 'module' or 'program' directives. It is therefore best to
place all 'ext' directives at the very top of the module.
4.4 Running A Compiled Program Stand-alone
This method should only be used when the program doesn't need the
facilities of the interpreter, such as the 'assert' predicate or
tracing. The program will have a high-segment containing only the
code for the facilities it uses.
No 'program' or 'module' directives should be given.
The starting point (predicate) of the program should have no
arguments and should have the external name 'start' given by an 'ext'
directive. For example:-
:-ext(do,0,start).
:-entry(do,0).
do :- hello,blabla(X),eat(X,Y),write(Y),bye.
.
.
.
Page 30
To compile and load the program, do as described in Section 4.1,
except that the switch "/n" should be appended to the program name in
the compilation command, eg.:-
R PLC
program:MYJOB/N
: etc.
←←←←
Page 31
5.0 BUILT-IN PROCEDURES
Built-in procedures are also referred to as evaluable predicates.
←←←←←←←←← ←←←←←←←←←←
5.1 Input / Output
A total of fourteen I/O streams may be open at any one time for
input and output. An extra stream is available, for input and output
to the user's terminal. A stream to a file F is opened for input by
←
the first "see(F)" executed. F then becomes the current input stream.
← ←
Similarly, a stream to file H is opened for output by the first
←
"tell(H)" executed. H then becomes the current output stream.
← ←
Subsequent calls to "see(F)" or to "tell(H)" make F or H the current
← ← ← ←
input or output stream, respectively. Any input or output is always
to the current stream.
When no input or output stream has been specified, the standard
ersatz file 'user', denoting the user's terminal, is utilized for
input and/or output. Terminal output is only displayed after a
newline is written or 'ttyflush' is called. When the terminal is
waiting for input on a new line, the prompt '|' is displayed.
When the current input and/or output stream is closed, the user's
terminal becomes the current input and/or output stream.
No file except the ersatz file 'user' can be simultaneously open
for input and output.
A file is referred to by its name, written as an atom, eg.
←←←←←←← ←← ←← ←←←←
myfile
'123'
'DATA.LST'
'DTA1:ABC.PL'
Note that reference to directories other than the user's is not
possible at present.
All I/O errors normally cause an 'abort', except for the effect
of the evaluable predicate 'nofileerrors' decribed below.
End of file is signalled by issuing a ↑Z (decimal 26) character.
Any more input requests for a file whose end has been reached causes
an error failure. ↑Z typed at the terminal causes the equivalent
condition for the ersatz file 'user'.
consult(F)
←
Instructs the interpreter to read-in the program which is in file
F. When a directive is read it is immediately executed. When a
←
clause is read it is put after any clauses already read by the
interpreter for that procedure. The consulted file may define
Page 32
its own character convention ('LC' or 'NOLC') without affecting
the convention prevailing outside.
reconsult(F)
←
Like 'consult' except that any procedure defined in the
"reconsulted" file erases any clauses for that procedure already
present in the interpreter. 'reconsult', used in conjunction
with 'save' and 'restore', facilitates the amendment of a program
without having to consult again from scratch all the files which
make up the program. The file "reconsulted" is normally a
temporary "patch" file containing only the amended procedure(s).
Note that it is possible to call 'reconsult(user)' and then enter
a patch directly on the terminal (ending with ":-end." or ↑Z).
This is only recommended for small, tentative patches.
see(F)
←
File F becomes the current input stream.
←
seeing(F)
←
F is unified with the name of the current input file.
←
seen
Closes current input stream.
tell(F)
←
File F becomes the current output stream.
←
telling(F)
←
F is unified with the name of the current output file.
←
told
Closes the current output stream.
close(F)
←
File F, currently open for input or output, is closed.
←
read(X)
←
The next term, delimited by a "fullstop" (ie. a '.' followed by
<cr> or a space), is read from the current input stream and
unified with X. The syntax of the term must accord with current
←
operator declarations. If a call 'read(X)' causes the end of the
←
current input stream to be reached, X is unified with the term
←
":-end". Further calls to 'read' for the same stream will then
cause an error failure.
Page 33
write(X)
←
The term X is written to the current output stream according to
←
current operator declarations.
nl
A new line is started on the current output stream.
display(X)
←
The term X is displayed on the terminal in standard parenthesised
←
prefix notation.
ttynl
A new line is started on the terminal and the buffer is flushed.
ttyflush
Flushes the terminal output buffer.
ttyget0(N)
←
N is the ASCII code of the next character input from the
←
terminal.
ttyget(N)
←
N is the ASCII code of the next non-blank printable character
←
from the terminal.
ttyskip(N)
←
Skips to just past the next ASCII character code N from the
←
terminal. N may be an integer expression.
←
ttyput(N)
←
The ASCII character code N is output to the terminal. N may be
← ←
an integer expression.
get0(N)
←
N is the ASCII code of the next character from the current input
←
stream.
get(N)
←
N is the ASCII code of the next non-blank printable character
←
from the current input stream.
skip(N)
←
Page 34
Skips to just past the next ASCII character code N from the
←
current input stream. N may be an integer expression.
←
put(N)
←
ASCII character code N is output to the current output stream. N
← ←
may be an integer expression.
tab(N)
←
N spaces are output to the current output stream. N may be an
← ←
integer expression.
putatom(X)
←
The name of atom X is output to the current output stream.
←
fileerrors
Undoes the effect of 'nofileerrors'.
nofileerrors
After a call to this predicate, the I/O error conditions
"incorrect file name ...", "can't see file ...", "can't tell file
..." and "end of file ..." cause a call to 'fail' instead of the
default action, which is to type an error message and then call
'abort'.
rename(F,N)
← ←
If file F is currently open, closes it and renames it to N. If N
← ← ←
is '[]', deletes the file.
log
Enables the logging of terminal interaction to file PROLOG.LOG.
It is the default.
nolog
Disables the logging of terminal interaction.
5.2 Arithmetic
Arithmetic is performed by built-in procedures which take as
arguments integer expressions and evaluate them. An integer
←←←←←←← ←←←←←←←←←←← ←←←←←←←←
expression is a term built from evaluable functors, integers and
←←←←←←←←← ←←←←←←←←
variables. At the time of evaluation, each variable in an integer
expression must be bound to an integer, or, for the interpreter ONLY,
to an integer expression. Although Prolog integers must be in the
range -2↑17 to 2↑17-1, the integers in arguments to arithmetic
procedures and the intermediate results of the evaluation may range
Page 35
from -2↑35 to 2↑35-1.
Each evaluable functor stands for an arithmetic operation. The
evaluable functors are as follows, where X and Y are integer
← ←
expressions:-
X+Y integer addition
← ←
X-Y integer subtraction
← ←
X*Y integer multiplication
← ←
X/Y integer division
← ←
X mod Y X modulo Y
← ← ← ←
-X unary minus
←
X/\Y bitwise conjunction
← ←
X\/Y bitwise disjunction
← ←
\X bitwise negation
←
X<<Y bitwise left shift of X by Y places
← ← ← ←
X>>Y bitwise right shift of X by Y places
← ← ← ←
!(X) the number in the range 0 to 2↑18-1
←
which is equal to X modulo 2↑18
←
$(X) the number in the range -2↑17 to 2↑17-1
←
which is equal to X modulo 2↑18
←
[X] evaluates to X if X is an integer
← ← ←
(therefore eg. "A" behaves within arithmetic
expressions as an integer constant which
is the ASCII code for letter A)
The arithmetic built-in procedures are as follows, where X and Y
← ←
stand for arithmetic expressions, and Z for some term:-
←
Z is X
← ←
Integer expression X is evaluated and the result, reduced modulo
←
2↑18 to a number in the range -2↑17 to 2↑17-1, is unified with Z.
←
Fails if X is not an integer expression.
←
X=:=Y
← ←
The values of X and Y are equal.
← ←
Page 36
X=\=Y
← ←
The values of X and Y are not equal.
← ←
X < Y
← ←
The value of X is less than the value of Y.
← ←
X > Y
← ←
The value of X is greater than the value of Y.
← ←
X =< Y
← ←
The value of X is less than or equal to the value of Y.
← ←
X >= Y
← ←
The value of X is greater than or equal to the value of Y.
← ←
5.3 Convenience
P,Q
← ←
P and Q.
← ←
P;Q
← ←
P or Q.
← ←
true
Always succeeds.
X=Y
← ←
Defined as if by clause " Z=Z. ".
length(L,N)
← ←
L must be instantiated to a list of determinate length. This
←
length is unified with N.
←
5.4 Extra Control
!
See Section 2.3.
not(P)
←
Page 37
If the goal P has a solution, fail, otherwise succeed. It is
←
defined as if by:-
not(P) :- P, !, fail.
not(←).
Not yet available for compiled code.
P -> Q; R
← ← ←
Analogous to
"if P then Q else R"
← ← ←
ie. defined as if by:-
P -> Q; R :- P, !, Q.
P-> Q; R :- R.
Not yet available for compiled code.
P -> Q
← ←
When occurring other than as one of the alternatives of a
disjunction, is equivalent to:-
P -> Q; fail.
← ←
Not yet available for compiled code.
repeat
Generates an infinite sequence of bactracking choices. It
behaves (but doesn't use store!) as if defined by the clauses:-
repeat.
repeat :- repeat.
fail
Always fails.
abort
Aborts the current execution. Refer to Section 3.11.
5.5 Meta-Logical
var(X)
←
Tests whether X is currently instantiated to a variable.
←
Page 38
nonvar(X)
←
Tests whether X is currently instantiated to a non-variable term.
←
atom(X)
←
Checks that X is currently instantiated to an atom (ie. a
←
non-variable term of arity 0, other than an integer).
integer(X)
←
Checks that X is currently instantiated to an integer.
←
atomic(X)
←
Checks that X is currently instantiated to an atom or integer.
←
X == Y
← ←
Tests if the terms currently instantiating X and Y are literally
← ←
identical (in particular, variables in equivalent positions in
the two terms must be identical).
X \== Y
← ←
Tests if the terms currently instantiating X and Y are not
← ←
literally identical.
functor(T,F,N)
← ← ←
The principal functor of term T has name F and arity N, where F
← ← ← ←
is either an atom or, provided N is 0, an integer. Initially,
←
either T must be instantiated to a non-variable, or F and N must
← ← ←
be instantiated to, respectively, either an atom and a
non-negative integer or an integer and 0. If these conditions are
not satisfied, an error message is given. In the case where T is
←
initially instantiated to a variable, the result of the call is
to instantiate T to the most general term having the principal
←
functor indicated.
arg(I,T,X)
← ← ←
Initially, I must be instantiated to a positive integer and T to
← ←
a compound term. The result of the call is to unify X with the
←
Ith argument of term T. (The arguments are numbered from 1
← ←
upwards.) If the initial conditions are not satisfied or I is out
←
of range, the call merely fails.
X=..Y
← ←
Y is a list whose head is the atom corresponding to the principal
←
functor of X and whose tail is the argument list of that functor
←
in X. eg.:-
←
Page 39
product(0,N,N-1) =.. [product,0,N,N-1]
N-1 =.. [-,N,1]
product =.. [product]
If X is instantiated to a variable, then Y must be instantiated
← ←
to a list of determinate length whose head is atomic (ie. an
atom or integer).
name(X,L)
← ←
If X is an atom or integer then L is a list of the ASCII codes of
← ←
the characters comprising the name of X. eg.:-
←
name(product,[112,114,111,100,117,99,116])
ie. name(product,"product")
name(1976,[49,57,55,54])
name(:-,[58,45])
name([],"[]")
If X is instantiated to a variable, L must be instantiated to a
← ←
list of ASCII character codes. eg.:-
?-name(X,[58,45]).
X = :-
?-name(X,":-").
X = :-
call(X)
←
If X is instantiated to a term which would be acceptable as body
←
of a clause, the goal 'call(X)' is executed exactly as if that
←
term appeared textually in place of the 'call(X)'. In particular,
←
any cut ('!') occurring in X is interpreted as if it occurred in
←
the body of the clause containing 'call(X)', unless that clause
←
is a compiled clause, in which case only the alternatives in the
execution of X are cut. If X is not instantiated as described
← ←
above, an error message is printed and 'call' fails.
X
←
(where X is a variable) Exactly the same as 'call(X)'.
← ←
assert(C)
←
Page 40
The current instance of C is interpreted as a clause and is added
←
to the current interpreted program (with new private variables
replacing any uninstantiated variables). The position of the new
clause within the procedure concerned is implementation-defined.
C must be instantiated to a non-variable.
←
asserta(C)
←
Like 'assert(C)', except that the new clause becomes the first
←
clause for the procedure concerned.
assertz(C)
←
Like 'assert(C)', except that the new clause becomes the last
←
clause for the procedure concerned.
clause(P,Q)
← ←
P must be bound to a non-variable term, and the current
←
interpreted program is searched for clauses whose head matches P.
←
The head and body of those clauses are unified with P and Q
← ←
respectively. If one of the clauses is a unit clause, Q will be
←
unified with 'true'.
retract(C)
←
The first clause in the current interpreted program that matches
C is erased. C must be initially instantiated to a non-variable,
← ←
and becomes unified with the value of the erased clause. The
space occupied by the erased clause will be recovered when
instances of the clause are no longer in use.
retractall(P)
←
All clauses in the current interpreted program whose head matches
P are 'retract'ed. P must be bound to a non-variable term.
← ←
listing(A)
←
Lists in the current output stream all the interpreted clauses
for predicates with name A, where A is bound to an atom.
← ←
listing
Lists in the current output stream all the clauses in the current
interpreted program.
Note: If a clause contains any atom or functor whose
←←←←
name has to be written in quotes, the listing of that
clause will be still readable, but syntactically
incorrect. Otherwise, clauses listed to a file by
'listing(A)' or 'listing' can be consulted back.
←
numbervars(X,N,M)
← ← ←
Page 41
Unifies each of the variables in term X with a special term, so
←
that 'write(X)' prints each of those variables as "←I", where the
← ←
Is are consecutive integers from N to M-1. N must be instantiated
← ← ← ←
to an integer.
ancestors(L)
←
Unifies L with a list of ancestor goals for the current clause.
←
The list starts with the parent goal and ends with the most
recent ancestor coming from a 'call' in a compiled clause. Not
available for compiled code.
subgoal←of(S)
←
The goal 'subgoal←of(S)' is equivalent to the sequence of goals:-
←
ancestors(L), in(S,L)
←
where the predicate 'in' successively matches its first argument
with each of the elements of its second argument. Not available
for compiled code.
5.6 Internal Database
These predicates remain in the system purely for compatibility
reasons, and will be removed at some future date.
record(X)
←
The current instance of X is "recorded" in the internal database
←
at some implementation-defined position in the sequence of terms
which constitutes the internal database (with new private
variables replacing any uninstantiated variables). X must be
←
instantiated to a non-variable.
recorda(X)
←
Like 'record(X)', except that the new term is "recorded" at the
←
"top" of the internal database.
recordz(X)
←
Like 'record(X)', except that the new term is "recorded" at the
←
"bottom" of the internal database.
?(X)
←
The internal database is searched for previously "recorded" terms
which match the current instance of X (which must not be a
←
variable). These terms are successively unified with X in the
←
order in which they are recorded in the internal database.
Page 42
recorded(X,P)
← ←
The database is searched for previously "recorded" terms that
match the current instance of X (which must not be a variable).
←
These terms are successively unified with X in the order in which
←
they are recorded in the internal database. P is unified with a
←
"pointer" which identifies the "recorded" term matching X. (A
←
"pointer" is a term whose internal structure is
implementation-defined).
instance(P,X)
← ←
X is unified with the database term identified by "pointer" P.
← ←
erase(P)
←
The database term identified by "pointer" P is erased from the
←
internal database. The space occupied by the erased term will be
recovered when instances of the term are no longer in use.
eraseall(X)
←
All the database terms matching the current instance of X are
←
"erased", in the sense of 'erase(←)'.
5.7 Environmental
'NOLC'
Establishes the "no lower-case" convention described in Section
3.1.
'LC'
Establishes the "full character set" convention described in
Section 3.1. It is the default setting.
trace
Enable trace. Consult Section 3.9 .
notrace
Disable trace. It is the default setting.
leash
Enable 'leashed' mode for tracing. It is the default setting.
unleash
Disable 'leashed' mode for tracing.
Page 43
op(priority,type,name)
←←←←←←←← ←←←← ←←←←
Treat name name as an operator of the stated type and priority
←←←← ←←←← ←←←←←←←←
(refer to Section 2.4). name may also be a list of names in which
←←←←
case all are to be treated as operators of the stated type and
←←←←
priority.
←←←←←←←←
break
Causes the current execution to be interrupted at the next
interpreted procedure call. Then the message " % break: " is
displayed. The interpreter is then ready to accept input as
though it was at top level. To close the break and resume the
execution which was suspended, the command " :-end. " or ↑Z must
be typed. Execution will be resumed at the procedure call where
it had been suspended. Alternatively, the suspended execution
can be aborted by calling the evaluable predicate 'abort'. Refer
to Section 3.8.
save(F)
←
The system saves the current state of the system into file F.
←
Refer to Sections 3.5 and 3.8 .
core←image
Prepares a core image of the current Prolog state which can be
saved with the 'SAVE' Monitor command and later run with the
'RUN' Monitor command.
restore(F)
←
The system is returned to the system state previously saved to
file F. Refer to Sections 3.6 and 3.8.
←
maxdepth(D)
←
Positive integer D specifies the maximum depth, ie. invocation
←
level, beyond which the system will induce an automatic failure.
Top level has zero depth. This is useful for guarding against
loops in an untested program, or for curtailing infinite
execution branches.
depth(D)
←
Integer D will give indication of current level of invocation.
←
gcguide(N)
←
N must be instantiated to an integer from 0 to 512, indicating
←
the desirable threshold of global stack pages below which garbage
collection should be avoided if possible. The default is N=6.
←
gc
Page 44
Enables garbage collection of the global stack (the default).
nogc
Disables garbage collection of the global stack.
trimcore
Reduces free space on the stacks and trail as much as possible
and, in virtual memory Monitors only, releases core no longer
needed, thereby reducing the size of the low segment. The
interpreter automatically calls 'trimcore' after each directive
at top-level, after an 'abort' and after a (re)consult.
statistics
Display on the terminal statistics relating to core usage, run
time, garbage collection of the global stack and stack shifts.
statistics(K,V)
← ←
This allows a program to gather various execution statistics.
For each of the possible keys K, V is unified with a list of
← ←
values, as follows:-
Key Values
--- ------
core low-segment high-segment
heap size free
global←stack " "
local←stack " "
trail " "
runtime since start since previous
of Prolog 'statistics'
garbage←collection no. of GCs words freed time spent
stack←shifts no. of local no. of trail time spent
shifts shifts
Times are in milliseconds, sizes of areas in words. If a time
exceeds 129.071 sec., it will be returned as a term:-
xwd(T1,T2)
representing:-
T1*2↑18 + T2 mod 2↑18
Note that if such a term occurs in an interpreted arithmetic
expression, it will be evaluated correctly.
Page 45
6.0 DEFINITE CLAUSE GRAMMARS
Prolog's grammar rules provide a convenient notation for
←←←←←←← ←←←←←
expressing definite clause grammars [Colmerauer 1975] [Pereira &
←←←←←←←← ←←←←←← ←←←←←←←←
Warren 1978]. Definite clause grammars are an extension of the
well-known context-free grammars.
A grammar rule takes the general form:-
LHS --> RHS.
←←← ←←←
meaning "a possible form for LHS is RHS". Both RHS and LHS are
←←← ←←← ←←← ←←←
sequences of one or more items linked by the standard Prolog
conjunction operator ','.
Definite clause grammars extend context-free grammars in the
following ways:-
(1) A non-terminal symbol may be any Prolog term (other than a
variable or integer).
(2) A terminal symbol may be any Prolog term. To distinguish
terminals from non-terminals, a sequence of one or more terminal
symbols is written within a grammar rule as a Prolog list. An empty
sequence is written as the empty list '[]'. If the terminal symbols
are ASCII character codes, such lists can be written (as elsewhere) as
strings. An empty sequence is written as the empty list '[]' or '""'.
(3) Extra conditions, in the form of Prolog procedure calls, may be
included in the right-hand side of a grammar rule. Such procedure
calls are written enclosed in '{' '⎇' brackets.
(4) The left-hand side of a grammar rule consists of a non-terminal,
optionally followed by a sequence of terminals (again written as a
Prolog list).
(5) Alternatives may be stated explicitly in the right-hand side of a
grammar rule, using the disjunction operator ';' as in Prolog.
(6) The cut symbol may be included in the right-hand side of a grammar
rule, as in a Prolog clause. The cut symbol does not need to be
enclosed in '{' '⎇' brackets.
As an example, here is a simple grammar which parses an
arithmetic expression (made up of digits and operators) and computes
its value:-
expr(Z) --> term(X), "*", expr(Y), {Z is X * Y⎇.
expr(Z) --> term(X), "/", expr(Y), {Z is X / Y⎇.
expr(X) --> term(X).
term(Z) --> number(X), "+", term(Y), {Z is X + Y⎇.
term(Z) --> number(X), "-", term(Y), {Z is X - Y⎇.
term(Z) --> number(Z).
Page 46
number(C) --> "+", number(C).
number(C) --> "-", number(X), {C is -X⎇.
number(X) --> [C], {"0"=<C, C=<"9", X is C - "0"⎇.
In the last rule, C is the ASCII code of some digit.
The question:-
?- expr(Z,"-2+3*5+1",[])
will compute Z=14. The two extra arguments are explained below.
Now, in fact, grammar rules are merely a convenient "syntactic
sugar" for ordinary Prolog clauses. Each grammar rule takes an input
string, analyses some initial portion, and produces the remaining
portion (possibly enlarged) as output for further analysis. The
arguments required for the input and output strings are not written
explicitly in a grammar rule, but the syntax implicitly defines them.
We now show how to translate grammar rules into ordinary clauses by
making explicit the extra arguments.
A rule such as:-
p(X) --> q(X).
translates into:-
p(X,S0,S) :- q(X,S0,S).
If there is more than one non-terminal on the right-hand side, as in:-
p(X,Y) --> q(X), r(X,Y), s(Y).
then corresponding input and output arguments are identified, as in:-
p(X,Y,S0,S) :- q(X,S0,S1), r(X,Y,S1,S2), r(Y,S2,S).
Terminals are translated using the predicate 'c(S1,X,S2)', read
as "point S1 is connected by terminal X to point S2", and defined by
the single clause:-
c([X,..S],X,S).
Then, for instance:-
p(X) --> [go,to], q(X), [stop].
is translated by:-
p(X,S0,S) :-
c(S0,go,S1), c(S1,to,S2), q(X,S2,S3), c(S3,stop,S).
Page 47
Extra conditions expressed as explicit procedure calls naturally
translate as themselves, eg.
p(X) --> [X], {integer(X), X>0⎇, q(X).
translates to:-
p(X,S0,S) :- c(S0,X,S1), integer(X), X>0, q(X,S1,S).
Similarly, a cut is translated literally.
Terminals on the left-hand side of a rule translate into an
explicit list in the output argument of the main non-terminal, eg.
is(N), [not] --> [aint].
becomes:-
is(N,S0,[not,..S]) :- c(S0,aint,S).
Disjunction has a fairly obvious translation, eg.
args(X,Y) --> dir(X), [to], indir(Y); indir(Y), dir(X).
translates to:-
args(X,Y,S0,S) :-
dir(X,S0,S1), c(S1,to,S2), indir(Y,S2,S);
indir(Y,S0,S1), dir(X,S1,S).
Page 48
7.0 FULL SYNTAX
A Prolog program consists of a sequence of sentences. Each
←←←←←←←←
sentence is a Prolog term. How terms are interpreted as sentences is
←←←←
defined in Section 7.2 below. Note that a term representing a
sentence may be written in any of its equivalent syntactic forms. For
example, the 2-ary functor ':-' could be written in standard prefix
notation instead of as the usual infix operator.
Terms are written as sequences of tokens. Tokens are sequences
←←←←←
of characters which are treated as separate symbols. Tokens include
the symbols for variables, constants and functors, as well as
punctuation characters such as brackets and commas.
Section 7.3 below defines how lists of tokens are interpreted as
terms. Each list of tokens which is read in (for interpretation as a
term or sentence) has to be terminated by a full-stop token. Two
←←←←←←←←←
tokens must be separated by a space token if they could otherwise be
←←←←←
interpreted as a single token. Both space tokens and comment tokens
←←←←←←←
are ignored when interpreting the token list as a term. A comment may
appear at any point in a token list (separated from other tokens by
spaces where necessary).
Section 7.4 below defines how tokens are represented as strings
of characters. But first Section 7.1 describes the notation used in
the formal definition of Prolog syntax.
7.1 Notation
(1) Syntactic categories (or "non-terminals") are always underlined.
Depending on the section, a category may represent a class of either
terms, token lists, or character strings.
(2) A syntactic rule takes the general form:-
C --> F1 | F2 | F3
← ←← ←← ←←
which states that an entity of category C may take any of the
←
alternative forms F1, F2, F3, etc.
←← ←← ←←
(3) Certain definitions and restrictions are given in ordinary
English, enclosed in { ⎇ brackets.
← ←
(4) A category written as C... denotes a sequence of one or more Cs.
←←←← ←
(5) A category written as ?C denotes an optional C. Therefore ?C...
←← ← ←←←←←
denotes a sequence of zero or more Cs.
←
(6) A few syntactic categories have names with arguments, and rules in
which they appear may contain meta-variables in the form of underlined
capital letters. The meaning of such rules should be clear from
analogy with the definite clause grammars described in Section 6.
Page 49
(7) In Section 7.3, particular tokens of the category name are written
←←←←
as quoted atoms, while tokens which are individual punctuation
characters are written literally. To avoid confusion, the punctuation
character '|' is written underlined.
7.2 Syntax Of Sentences As Terms
sentence --> clause | directive | grammar-rule
←←←←←←←← ←←←←←← ←←←←←←←←← ←←←←←←←←←←←←
clause --> non-unit-clause | unit-clause
←←←←←← ←←←←←←←←←←←←←←← ←←←←←←←←←←←
directive --> command | question | file-list
←←←←←←←←← ←←←←←←← ←←←←←←←← ←←←←←←←←←
non-unit-clause --> ( head :- goals )
←←←←←←←←←←←←←←← ←←←← ←←←←←
unit-clause --> head
←←←←←←←←←←← ←←←←
{ where head is not otherwise a sentence ⎇
← ←←←← ←←←←←←←← ←
command --> ( :- goals )
←←←←←←← ←←←←←
question --> ( ?- goals )
←←←←←←←← ←←←←←
file-list --> list
←←←←←←←←← ←←←←
head --> term
←←←← ←←←←
{ where term is not an integer or variable ⎇
← ←←←← ←←←←←←← ←←←←←←←← ←
goals --> ( goals , goals )
←←←←← ←←←←← ←←←←←
| ( goals ; goals )
←←←←← ←←←←←
| goal
←←←←
goal --> term
←←←← ←←←←
{ where term is not an integer
← ←←←← ←←←←←←←
and is not otherwise a goals ⎇
←←←←← ←
grammar-rule --> ( gr-head --> gr-body )
←←←←←←←←←←←← ←←←←←←← ←←←←←←←
gr-head --> non-terminal
←←←←←←← ←←←←←←←←←←←←
| ( non-terminal , terminals )
←←←←←←←←←←←← ←←←←←←←←←
gr-body --> ( gr-body , gr-body )
←←←←←←← ←←←←←←← ←←←←←←←
| ( gr-body ; gr-body )
←←←←←←← ←←←←←←←
| non-terminal
←←←←←←←←←←←←
| terminals
←←←←←←←←←
| gr-condition
←←←←←←←←←←←←
non-terminal --> term
←←←←←←←←←←←← ←←←←
{ where term is not an integer or variable
← ←←←←
and is not otherwise a gr-body ⎇
←←←←←←← ←
terminals --> list | string
←←←←←←←←← ←←←← ←←←←←←
Page 50
gr-condition --> { goals ⎇
←←←←←←←←←←←← ←←←←←
7.3 Syntax Of Terms As Tokens
term-read-in --> subterm(1200) full-stop
←←←←←←←←←←←← ←←←←←←←←←←←←← ←←←←←←←←←
subterm(N) --> term(M) { where M is less than or equal to N ⎇
←←←←←←←←←← ←←←←←←← ← ← ← ←
term(N) --> op(N,fx)
←←←←←←← ←←←←←←←←
| op(N,fy)
←←←←←←←←
| op(N,fx) subterm(N-1)
←←←←←←←← ←←←←←←←←←←←←
{ except the case '-' number ⎇
← ←←←←←← ←
{ if subterm starts with a '(',
← ←←←←←←←
op must be followed by a space ⎇
←← ←←←←← ←
| op(N,fy) subterm(N)
←←←←←←←← ←←←←←←←←←←
{ if subterm starts with a '(',
← ←←←←←←←
op must be followed by a space ⎇
←← ←←←←← ←
| subterm(N-1) op(N,xfx) subterm(N-1)
←←←←←←←←←←←← ←←←←←←←←← ←←←←←←←←←←←←
| subterm(N-1) op(N,xfy) subterm(N)
←←←←←←←←←←←← ←←←←←←←←← ←←←←←←←←←←
| subterm(N) op(N,yfx) subterm(N-1)
←←←←←←←←←← ←←←←←←←←← ←←←←←←←←←←←←
| subterm(N-1) op(N,xf)
←←←←←←←←←←←← ←←←←←←←←
| subterm(N) op(N,yf)
←←←←←←←←←← ←←←←←←←←
term(1000) --> subterm(999) , subterm(1000)
←←←←←←←←←← ←←←←←←←←←←←← ←←←←←←←←←←←←←
term(0) --> functor ( arguments )
←←←←←←← ←←←←←←← ←←←←←←←←←
{ provided there is no space between
← ←←←←←
the functor and the '(' ⎇
←←←←←←← ←
| ( subterm(1200) )
←←←←←←←←←←←←←
| { subterm(1200) ⎇
←←←←←←←←←←←←←
| list
←←←←
| string
←←←←←←
| constant
←←←←←←←←
| variable
←←←←←←←←
op(N,T) --> functor
←←←←←←← ←←←←←←←
{ where functor has been declared as an
← ←←←←←←←
operator of type T and precedence N ⎇
← ← ←
arguments --> subterm(999)
←←←←←←←←← ←←←←←←←←←←←←
| subterm(999) , arguments
←←←←←←←←←←←← ←←←←←←←←←
list --> '[]'
←←←←
| [ listexpr ]
←←←←←←←←
listexpr --> subterm(999)
←←←←←←←← ←←←←←←←←←←←←
| subterm(999) , listexpr
←←←←←←←←←←←← ←←←←←←←←
| subterm(999) | subterm(999)
←←←←←←←←←←←← ← ←←←←←←←←←←←←
| '..' subterm(999)
←←←←←←←←←←←←
Page 51
constant --> atom | integer
←←←←←←←← ←←←← ←←←←←←←
atom --> name { where name is not a prefix operator ⎇
←←←← ←←←← ← ←←←← ←
integer --> number
←←←←←←← ←←←←←←
| '-' number
←←←←←←
functor --> name
←←←←←←← ←←←←
7.4 Syntax Of Tokens As Character Strings
token --> name
←←←←← ←←←←
| number
←←←←←←
| variable
←←←←←←←←
| string
←←←←←←
| punctuation-char
←←←←←←←←←←←←←←←←
| decorated-bracket
←←←←←←←←←←←←←←←←←
| space
←←←←←
| comment
←←←←←←←
| full-stop
←←←←←←←←←
name --> quoted-name
←←←← ←←←←←←←←←←←
| word
←←←←
| symbol
←←←←←←
| solo-char
←←←←←←←←←
| []
| {⎇
quoted-name --> ' quoted-item... '
←←←←←←←←←←← ←←←←←←←←←←←←←←
quoted-item --> char { other than ' ⎇
←←←←←←←←←←← ←←←← ← ←
| ''
word --> capital-letter ?alpha...
←←←← ←←←←←←←←←←←←←← ←←←←←←←←←
{ in the 'NOLC' convention only ⎇
← ←
word --> small-letter ?alpha...
←←←← ←←←←←←←←←←←← ←←←←←←←←←
symbol --> symbol-char...
←←←←←← ←←←←←←←←←←←←←←
{ except in the case of a full-stop
← ←←←←←←←←←
or where the first 2 chars are /* ⎇
←
number --> digit...
←←←←←← ←←←←←←←←
| digit ' digit...
←←←←← ←←←←←←←←
variable --> underline ?alpha...
←←←←←←←← ←←←←←←←←← ←←←←←←←←←
variable --> capital-letter ?alpha..
←←←←←←←← ←←←←←←←←←←←←←← ←←←←←←←←
{ in the 'LC' convention only ⎇
← ←
Page 52
string --> " ?string-item... "
←←←←←← ←←←←←←←←←←←←←←←
string-item --> char { other than " ⎇
←←←←←←←←←←← ←←←← ← ←
| ""
decorated-bracket --> %(
←←←←←←←←←←←←←←←←←
| %)
space --> space-char...
←←←←← ←←←←←←←←←←←←←
comment --> /* ?char... */
←←←←←←← ←←←←←←←←
{ where ?char... must not contain */ ⎇
← ←←←←←←←← ←
full-stop --> . space-char
←←←←←←←←← ←←←←←←←←←←
char --> { any ASCII character, ie. ⎇
←←←← ← ←
space-char
←←←←←←←←←←
| alpha
←←←←←
| symbol-char
←←←←←←←←←←←
| solo-char
←←←←←←←←←
| punctuation-char
←←←←←←←←←←←←←←←←
| quote-char
←←←←←←←←←←
space-char --> { any ASCII character code up to 32,
←←←←←←←←←← ←
includes <blank>, <cr> and <lf> ⎇
←
alpha --> letter | digit | underline
←←←←← ←←←←←← ←←←←← ←←←←←←←←←
letter --> capital-letter | small-letter
←←←←←← ←←←←←←←←←←←←←← ←←←←←←←←←←←←
capital-letter --> { any character from the list
←←←←←←←←←←←←←← ←
ABCDEFGHIJKLMNOPQRSTUVWXYZ ⎇
←
small-letter --> { any character from the list
←←←←←←←←←←←← ←
abcdefghijklmnopqrstuvwxyz ⎇
←
digit --> { any character from the list
←←←←← ←
012346789 ⎇
←
symbol-char --> { any character from the list
←←←←←←←←←←← ←
+-*/\↑<>=`}:.?@#$& ⎇
←
solo-char --> { any character from the list
←←←←←←←←← ←
;!% ⎇
←
punctuation-char --> { any character from the list
←←←←←←←←←←←←←←←← ←
()[]{⎇,| ⎇
←
quote-char --> { any character from the list
←←←←←←←←←← ←
'" ⎇
←
underline --> { the character ← ⎇
←←←←←←←←← ← ←
Page 53
7.5 Notes
(1) The expression of precedence 1000 (ie. belonging to syntactic
category term(1000)) which is written:-
←←←←←←←←←←
X,Y
← ←
denotes the term ','(X,Y) in standard syntax.
← ←
(2) The bracketed expression (belonging to syntactic category
term(0)):-
←←←←←←←
(X)
←
denotes simply the term X.
←
(3) The curly-bracketed expression (belonging to syntactic category
term(0)):-
←←←←←←←
{X⎇
←
denotes the term '{⎇'(X) in standard syntax.
←
(4) The decorated brackets '%(' and '%)' are alternatives for the
curly brackets '{' and '⎇' respectively. eg.
{X⎇ = %(X%)
(5) The character '|' is allowed as an alternative to ',..' in lists,
eg.
[X|L] = [X,..L]
(6) Note that, for example, ' -3 ' denotes an integer whereas ' -(3) '
denotes a compound term which has the 1-ary functor '-' as its
principal functor.
(7) The character " within a string must be written duplicated.
Similarly for the character ' within a quoted atom.
Page 54
8.0 RESERVED NAMES
Note, in addition to the list of reserved predicates which
follows, that names containing the character "$" are reserved for
system use and should not be used.
abort ancestors(←) arg(←,←,←) assert(←) asserta(←) assertz(←) atom(←)
atomic(←)
break
c(←,←,←) call(←) clause(←,←) close(←) compactcode consult(←)
core←image
depth(←) display(←)
end entry(←) entry(←,←) erase(←) eraseall(←) ext(←) ext(←,←,←)
fail fastcode fileerrors functor(←,←,←)
gc gcguide(←) get(←) get0(←)
halt instance(←,←) integer(←) is(←,←)
'LC' leash length(←) listing listing(←) log
maxdepth(←) mode(←) module(←,←)
name(←,←) nl 'NOLC' nofileerrors nogc nolog nonvar(←) not(←) notrace
numbervars(←,←,←)
op(←,←,←)
program(←,←) put(←) putatom(←)
read(←) reconsult(←) record(←) recorda(←) recorded(←,←) recordz(←)
repeat rename(←,←) restore(←) retract(←) retractall(←)
save(←) see(←) seeing(←) seen skip(←) statistics statistics(←,←)
subgoal←of(←)
tab(←) tell(←) telling(←) told trace trimcore true ttyflush ttyget(←)
ttyget0(←) ttynl ttyput(←) ttyskip(←)
unleash
var(←) version(←,←,←,←)
write(←)
!
','(←,←)
;(←,←)
=(←,←)
<(←,←)
>(←,←)
>=(←,←)
=<(←,←)
=..(←,←)
==(←,←)
\==(←,←)
=:=(←,←)
=\=(←,←)
->(←,←)
Page 55
9.0 EXAMPLES
Some simple examples of Prolog programming are given below. To
clearly differentiate the examples themselves, they are marked with a
vertical bar in the left margin.
9.1 Simple List Processing
The goal 'concatenate(L1,L2,L3)' is true if list L3 consists of
←← ←← ←← ←←
the elements of list L1 concatenated with the elements of list L2. The
←← ←←
goal 'member(X,L)' is true if X is one of the elements of list L. The
← ← ← ←
goal 'reverse(L1,L2)' is true if list L2 consists of the elements of
←← ←← ←←
list L1 in reverse order.
←←
| concatenate([X|L1],L2,[X|L3]) :- concatenate(L1,L2,L3).
| concatenate([],L,L).
|
| member(X,[X|L]).
| member(X,[←|L]) :- member(X,L).
|
| reverse(L,L1) :- reverse←concatenate(L,[],L1).
|
| reverse←concatenate([X|L1],L2,L3) :-
| reverse←concatenate(L1,[X|L2],L3).
| reverse←concatenate([],L,L).
9.2 A Small Database
The goal 'descendant(X,Y)' is true if Y is a descendant of X.
← ← ← ←
| descendant(X,Y) :- offspring(X,Y).
| descendant(X,Z) :- offspring(X,Y), descendant(Y,Z).
|
| offspring(abraham,ishmael).
| offspring(abraham,isaac).
| offspring(isaac,esau).
| offspring(isaac,jacob).
If for example the question:-
?- descendant(abraham,X).
is executed, Prolog's backtracking results in different descendants of
Abraham being returned as successive instances of the variable X, ie.
X = ishmael
X = isaac
X = esau
X = jacob
Page 56
9.3 Quick-Sort
The goal 'qsort(L,[],R)' is true if list R is a sorted version of
← ← ←
list L. More generally, 'qsort(L,R0,R)' is true if list R consists of
← ← ←← ← ←
the members of list L sorted into order, followed by the members of
←
list R0. The algorithm used is a variant of Hoare's "Quick Sort".
←←
| :-mode qsort(+,+,-).
| :-mode partition(+,+,-,-).
|
| qsort([X|L],R0,R) :-
| partition(L,X,L1,L2),
| qsort(L2,R0,R1),
| qsort(L1,[X|R1],R).
| qsort([],R,R).
|
| partition([X|L],Y,[X|L1],L2) :- X =< Y, !,
| partition(L,Y,L1,L2).
| partition([X|L],Y,L1,[X|L2]) :- X > Y, !,
| partition(L,Y,L1,L2).
| partition([],←,[],[]).
9.4 Differentiation
The goal 'd(E1,X,E2)' is true if expression E2 is a possible form
←← ← ←← ←←
for the derivative of expression E1 with respect to X.
←← ←
| :-mode d(+,+,-).
| :-op(300,xfy,↑).
|
| d(U+V,X,DU+DV) :-!, d(U,X,DU), d(V,X,DV).
| d(U-V,X,DU-DV) :-!, d(U,X,DU), d(V,X,DV).
| d(U*V,X,DU*V+U*DV) :-!, d(U,X,DU), d(V,X,DV).
| d(U↑N,X,N*U↑N1*DU) :-!, integer(N), N1 is N-1, d(U,X,DU).
| d(-U,X,-DU) :-!, d(U,X,DU).
| d(exp(U),X,exp(U)*DU) :-!, d(U,X,DU).
| d(log(U),X,DU/U) :-!, d(U,X,DU).
| d(X,X,1) :-!.
| d(C,X,0) :- atomic(C), C \== 0, !.
Page 57
9.5 Mapping A List Of Items Into A List Of Serial Numbers
The goal 'serialise(L1,L2)' is true if L2 is a list of serial
←← ←← ←←
numbers corresponding to the members of list L1, where the members of
←←
L1 are numbered (from 1 upwards) in order of increasing size.
←←
eg. ?-serialise([1,9,7,7],X). gives X = [1,3,2,2].
| serialise(Items,SerialNos) :-
| pairlists(Items,SerialNos,Pairs),
| arrange(Pairs,Tree),
| numbered(Tree,1,N).
|
| pairlists([X|L1],[Y|L2],[pair(X,Y)|L3]) :- pairlists(L1,L2,L3).
| pairlists([],[],[]).
|
| arrange([X|L],tree(T1,X,T2)) :-
| split(L,X,L1,L2),
| arrange(L1,T1),
| arrange(L2,T2).
| arrange([],void).
|
| split([X|L],X,L1,L2) :-!, split(L,X,L1,L2).
| split([X|L],Y,[X|L1],L2) :- before(X,Y),!, split(L,Y,L1,L2).
| split([X|L],Y,L1,[X|L2]) :- before(Y,X),!, split(L,Y,L1,L2).
| split([],←,[],[]).
|
| before(pair(X1,Y1),pair(X2,Y2)) :- X1 < X2.
|
| numbered(tree(T1,pair(X,N1),T2),N0,N) :-
| numbered(T1,N0,N1),
| N2 is N1+1,
| numbered(T2,N2,N).
| numbered(void,N,N).
9.6 Use Of Meta-Predicates
This example illustrates the use of the meta-predicates 'var' and
'=..'. The procedure call 'variables(Term,L,[])' instantiates variable
←←←←
L to a list of all the variable occurrences in the term Term.
←←←←
eg. variables(d(U*V,X,DU*V+U*DV), [U,V,X,DU,V,U,DV], []).
| variables(X,[X|L],L) :- var(X),!.
| variables(T,L0,L) :- T =.. [F|A], variables1(A,L0,L).
|
| variables1([T|A],L0,L) :- variables(T,L0,L1), variables1(A,L1,L).
| variables1([],L,L).
Page 58
9.7 Prolog In Prolog
This example shows how simple it is to write a Prolog interpreter
in Prolog, and illustrates the use of a variable goal. In this
mini-interpreter, goals and clauses are represented as ordinary Prolog
data structures (ie. terms). Terms representing clauses are specified
using the unary predicate 'clause', eg.
clause( (grandparent(X,Z):-parent(X,Y),parent(Y,Z)) ).
A unit clause will be represented by a term such as:-
( parent(john,mary) :- true )
The mini-interpreter consists of four clauses:-
| execute(true) :-!.
| execute((P,Q)) :- !, execute(P), execute(Q).
| execute(P) :- clause((P:-Q)), execute(Q).
| execute(P) :- P.
The last clause enables the mini-interpreter to cope with calls to
ordinary Prolog predicates, eg. evaluable predicates.
9.8 Translating Enlish Sentences Into Logic Formulae
The following example of a definite clause grammar defines in a
formal way the traditional mapping of simple English sentences into
formulae of classical logic. By way of illustration, if the
sentence:-
Every man that lives loves a woman.
is parsed as a 'sentence(P)', P will get instantiated to:-
all(X):(man(X)&lives(X) => exists(Y):(woman(Y)&loves(X,Y)))
where ':', '&' and '=' are infix operators defined by:-
:-op(900,xfx,=>).
:-op(800,xfy,&).
:-op(300,xfx,:).
The grammar follows:-
Page 59
| sentence(P) --> noun←phrase(X,P1,P), verb←phrase(X,P1).
|
| noun←phrase(X,P1,P) -->
| determiner(X,P2,P1,P), noun(X,P3), rel←clause(X,P3,P2).
| noun←phrase(X,P,P) --> name(X).
|
| verb←phrase(X,P) --> trans←verb(X,Y,P1), noun←phrase(Y,P1,P).
| verb←phrase(X,P) --> intrans←verb(X,P).
|
| rel←clause(X,P1,P1&P2) --> [that], verb←phrase(X,P2).
| rel←clause(←,P,P) --> [].
|
| determiner(X,P1,P2, all(X):(P1=>P2) ) --> [every].
| determiner(X,P1,P2, exists(X):(P1&P2) ) --> [a].
|
| noun(X, man(X) ) --> [man].
| noun(X, woman(X) ) --> [woman].
|
| name(john) --> [john].
|
| trans←verb(X,Y, loves(X,Y) ) --> [loves].
| intrans←verb(X, lives(X) ) --> [lives].
Page 60
10.0 REFERENCES
Colmerauer A [1975]
"Les Grammaires de Metamorphose".
Groupe d'Intelligence Artificielle,Marseille-Luminy. Nov 1975.
Appears as "Metamorphosis Grammars" in "Natural Language
Communication with Computers", Springer Verlag, 1978.
van Emden M H [1975]
"Programming with Resolution Logic".
Report CS-75-30, Dept.of Computer Science, University of
Waterloo, Canada. Nov 1975.
Kowalski R A [1974]
"Logic for Problem Solving".
DCL Memo 75, Dept of AI, Edinburgh. Mar 74.
Pereira F C N & Warren D H D [1978]
"Definite Clause Grammars Compared with Augmented Transition
Networks".
Forthcoming report, Dept. of AI, Edinburgh.
Robinson J A [1965]
"A Machine-Oriented Logic Based on the Resolution Principle".
JACM vol 12, pp.23-44. 1965.
Roussel P [1975]
"Prolog : Manuel de Reference et d'Utilisation".
Groupe d'Intelligence Artificielle, Marseille-Luminy. Sep 1975.
Warren D H D [1977]
"Implementing Prolog - Compiling Predicate Logic Programs".
Research reports 39 & 40, Dept. of AI, Edinburgh. 1977.
Warren D H D, Pereira L M, Pereira, F C N [1977]
"Prolog - the Language and its Implementation Compared with
Lisp".
Procs. of the ACM Symposium on Artificial Intelligence and
Programming Languages, SIGART/SIGPLAN Notices, Rochester, N.Y.,
Aug 1977.